﻿using Common.Core.Attributes;
using Common.Core.IoC;
using Common.Helpers;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace Common.Core.Extensions
{
    /// <summary>
    /// IServiceCollection自定义扩展
    /// </summary>
    public static class AppServiceCollectionExtensions
    {
        /// <summary>
        /// 添加自动扫描注入Service服务和Respository仓储等
        /// <para>
        /// 需要注意的是，遵循如下约定：
        /// IUserService --> UserService, IUserRepository --> UserRepository.
        /// </para>
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="startNamespace">前缀集合</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddAutoScanInjection(this IServiceCollection services, List<string> startNamespaces)
        {
            Dictionary<int, List<System.Type>> highestIoCs = new Dictionary<int, List<System.Type>>();

            RuntimeHelper.GetSaasAssemblies(startNamespaces).ToList().ForEach(a =>
            {
                a.GetTypes().Where(t => typeof(IPrivateDependency).IsAssignableFrom(t) && t.IsClass).ToList().ForEach(t =>
                {
                    var high = t.GetCustomAttribute<HighestIoCAttribute>(false)?.Level;
                    if (high != null)
                    {
                        if (highestIoCs.ContainsKey(high.ToInt()))
                        {
                            highestIoCs[high.ToInt()].Add(t);
                        }
                        else
                        {
                            highestIoCs.Add(high.ToInt(), new List<System.Type>() { t });
                        }
                    }
                    else
                    {
                        var serviceType = t.GetInterface($"I{t.Name}");

                        _serviceCollectionAdd(services, serviceType, t);
                    }
                });
            });

            if (highestIoCs.Count > 0)
            {
                foreach (KeyValuePair<int, List<System.Type>> k in highestIoCs.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value))
                {
                    foreach (var t in k.Value)
                    {
                        var serviceType = t.GetInterface($"I{t.Name}");
                        _serviceCollectionAdd(services, serviceType, t);
                    }
                }
            }

            return services;
        }

        static IServiceCollection _serviceCollectionAdd(IServiceCollection services, System.Type serviceType, System.Type t)
        {
            if ((serviceType ?? t).GetInterface(typeof(ISingletonDependency).Name) != null)
            {
                if (serviceType != null)
                {
                    services.AddSingleton(serviceType, t);
                }
                else
                {
                    services.AddSingleton(t);
                }
            }
            else if ((serviceType ?? t).GetInterface(typeof(IScopedDependency).Name) != null)
            {
                if (serviceType != null)
                {
                    services.AddScoped(serviceType, t);
                }
                else
                {
                    services.AddScoped(t);
                }
            }
            else if ((serviceType ?? t).GetInterface(typeof(ITransientDependency).Name) != null)
            {
                if (serviceType != null)
                {
                    services.AddTransient(serviceType, t);
                }
                else
                {
                    services.AddTransient(t);
                }
            }
            else
            {
                if (serviceType != null)
                {
                    services.AddTransient(serviceType, t);
                }
                else
                {
                    services.AddTransient(t);
                }
            }

            return services;
        }

    }
}